package org.dreamwork.jasmine2.restful;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * User: seth.yang
 * Date: 14-11-18
 * Time: 下午2:42
 */
public class APIInfoPage {
    private ServletContext application;

    public ServletContext getApplication () {
        return application;
    }

    public void setApplication (ServletContext application) {
        this.application = application;
    }

    @SuppressWarnings ("unchecked")
    public void render (HttpServletResponse response) throws IOException {
        PrintWriter writer = response.getWriter ();
        writer.write (
            "<!DOCTYPE html>\n" +
            "<html>\n" +
            "<head>\n" +
            "    <title>Restful API Info.</title>\n" +
            "    <style>\n" +
            "        * {font-size: 14px; font-family:\"Microsoft Yahei\", monospace;background-color: #f9f9f9;padding: 0;margin:0}\n" +
            "        #content {margin-left: 20px;}\n" +
            "        li {list-style: none}\n" +
            "\n" +
            "        .restful-api-title {font-size: 28px;}\n" +
            "        .api-item {margin: 0 auto 15px auto; padding:0;}\n" +
            "        .method-table {margin-bottom: 20px;margin-left: 20px;}\n" +
            "        .method-table td, .method-table th {padding: 5px; vertical-align: top;}\n" +
            "        .method-table th {text-align: left}\n" +
            "        .pattern {font-size: 20px;display: block; background-color: #b0e0e6; padding:10px;}\n" +
            "        .api-description {font-size: 18px; line-height: 180%; padding:10px;}\n" +
            "        .content-table {top: 20px; right: 20px; border: 1px solid #ccc;position: fixed}\n" +
            "        .content-table-item {color: #000; cursor: pointer; display: block; text-decoration: none; padding: 5px 10px;}\n" +
            "        .content-table-item:hover {background-color: #b0e0e6;}\n" +
            "        .content-table-header {background-color: #b0e0e6;font-weight: bold; text-align: left; padding: 10px;}\n" +
            "        .sub-content-table-item {padding-left: 30px;}\n" +
            "        .content-item {list-style: none;}\n" +
            "        .sub-table {border:1px solid #ccc; border-collapse: collapse}\n" +
            "        .sub-table td, .sub-table th {padding: 5px 20px 5px 5px; vertical-align: top; border-bottom: 1px dashed #ccc;}\n" +
            "        .sub-table-header th {background-color: #b0e0e6; border-bottom: 1px solid #ccc;}\n" +
            "        .method {margin-left: 20px;}\n" +
            "        .method-title {background-color: #b0e0e6; padding:10px;display: block}\n" +
            "        .transparent {filter: alpha(30);opacity: .3;}\n" +
            "        .secure-context {margin:10px auto; border:1px solid #ccc}\n" +
            "        .secure-context-list li {padding: 5px; font-size: 16px;}\n" +
            "        .secure-title {display:inline-block; width: 150px; font-weight:bold}\n" +
            "\n" +
            "        .close-button {\n" +
            "            margin-left: 60px;\n" +
            "            display:block;width:16px; height:16px;line-height:16px; cursor: pointer;\n" +
            "            text-align: center; border: 1px solid #ccc; background-color: #fff;color:#000;\n" +
            "            float: right;\n" +
            "        }\n" +
            "        .close-button:hover {color:#fff;background-color: #6495ed}\n" +
            "        #content-table-list {min-width:280px;max-height:500px;overflow:auto}" +
            "    </style>\n" +
            "</head>\n" +
            "<body>");
        Map<String, APIDefinition> map = (Map<String, APIDefinition>) application.getAttribute (RestfulAPIManager.KEY_API_MAPPING);
        if (map != null && !map.isEmpty ()) {
            writer.write (
                "<div class=\"content-table transparent\" id=\"content-table\">\n" +
                "    <h1 class=\"content-table-header\">\n" +
                "        <a class=\"close-button\" id=\"close-button\">+</a> Content Table \n" +
                "    </h1>\n" +
                "    <ul id=\"content-table-list\" style=\"display: none\">");
            for (APIDefinition api : map.values ()) {
                writer.printf (
                        "<li class=\"content-item\">\n" +
                        "<a class=\"content-table-item\" href=\"#%s\">%s</a>", api.getPattern(), api.getTitle ());
                if (!api.getMethods ().isEmpty ()) {
                    writer.println ("<ul>");
                    for (MethodDefinition md : api.getMethods ().values ()) {
                        writer.printf (
                            "<li class=\"content-item\">\n" +
                            "    <a class=\"content-table-item sub-content-table-item\" href=\"#%s/%s\">&#187; %s</a>\n" +
                            "</li>",
                            api.getPattern(), md.getPattern(), md.getTitle()
                        );
                    }
                    writer.println ("</ul>");
                }
                writer.println ("</li>");
            }
            writer.println ("</ul></div><div id=\"content\">");
            writer.println ("<h1 class=\"restful-api-title\">");
            writer.println (RestfulAPIContext.getTitle());
            writer.println ("</h1><div class=\"restful-api-description\">");
            writer.println (RestfulAPIContext.getDescription());
            writer.println ("</div>");

            if (RestfulAPIContext.secureContext != null) {
                writer.println ("<div class='secure-context'>");
                writer.println ("<h1 class='content-table-header'>Secure Context</h1>");
                writer.println ("<ul class='secure-context-list'>");
                if (RestfulAPIContext.secureContext.getBlockEncryption () != null) {
                    writer.println ("<li><span class='secure-title'>Block-Encryption</span>");
                    writer.println (RestfulAPIContext.secureContext.getBlockEncryption ().uri + "</li>");
                }
                if (RestfulAPIContext.secureContext.getKeyTransport () != null) {
                    writer.println ("<li><span class='secure-title'>Key-Wrap</span>");
                    writer.println (RestfulAPIContext.secureContext.getKeyTransport ().uri + "</li>");
                }
                if (RestfulAPIContext.secureContext.getSignature () != null) {
                    writer.println ("<li><span class='secure-title'>Signature</span>");
                    writer.println (RestfulAPIContext.secureContext.getSignature ().uri + "</li>");
                }
                writer.println ("</ul>");
                writer.println ("</div>");
            }

            for (APIDefinition api : map.values ()) {
                writer.println ("<div class=\"api-item\">");
                writer.printf ("<a class=\"pattern\" name=\"%s\">%s</a>%n", api.getPattern (), api.getTitle ());
                writer.printf ("<div class=\"api-description\">%s</div>%n", api.getTitle ());
                Map<String, MethodDefinition> methods = api.getMethods ();
                if (!methods.isEmpty ()) {
                    writer.println ("<div class=\"method\">");
                    for (MethodDefinition method : methods.values()) {
                        Collection<ContextParameterDefinition> c = method.getRequiredContextParameter ();
                        c.addAll (api.getRequiredContextParameter ());
                        StringBuilder builder = new StringBuilder ();
                        for (ContextParameterDefinition cpd : c) {
                            if (builder.length () > 0) builder.append ('&');
                            builder.append (cpd.getName ()).append ("=${").append (cpd.getName ().toUpperCase ()).append ("}");
                        }
                        MethodType type = method.getType ();
                        if (type == MethodType.GET) {
                            List<APIParameterDefinition> list = method.getParameters ();
                            for (APIParameterDefinition pd : list) {
                                if (builder.length () > 0) builder.append ('&');
                                builder.append (pd.getName ()).append ("=${").append (pd.getName ().toUpperCase ()).append ('}');
                            }
                        }
                        String url = api.getPattern () + '/' + method.getPattern ();
                        if (builder.length () > 0) url += "?" + builder;
                        writer.printf ("<a name=\"%s/%s\" class=\"method-title\">%s</a>%n", api.getPattern(), method.getPattern(), method.getTitle ());
                        writer.printf ("<table class=\"method-table\">%n");
                        writer.printf (
                            "<tr>\n" +
                            "    <th>URL</th>\n" +
                            "    <td class=\"padding5\">%s</td>\n" +
                            "</tr>%n", url);
                        writer.printf (
                            "<tr>\n" +
                            "    <th>Method</th>\n" +
                            "    <td class=\"padding5\">%s</td>\n" +
                            "</tr>%n", method.getType ());
                        writer.printf (
                            "<tr>\n" +
                            "    <th>Description</th>\n" +
                            "    <td>%s</td>\n" +
                            "</tr>%n", method.getDescription() == null ? "" : method.getDescription ());
                        if (!c.isEmpty ()) {
                            writer.println (
                                "<tr>\n" +
                                "<th>Context</th>\n" +
                                "<td>\n" +
                                "    <p>以下参数为调用该API的<strong>必须参数</strong>，并且<strong>无论是HTTP GET还是HTTP POST，都将出现在Query String 上</strong></p>\n" +
                                "    <table class=\"sub-table\">\n" +
                                "        <tr class=\"sub-table-header\">\n" +
                                "            <th>参数名</th>\n" +
                                "            <th>描述</th>\n" +
                                "        </tr>");
                            for (ContextParameterDefinition cpd : c) {
                                writer.printf (
                                    "<tr>\n" +
                                    "<th>%s</th>\n" +
                                    "<td>%s</td>\n" +
                                    "</tr>%n", cpd.getName(), cpd.getDescription() == null ? "" : cpd.getDescription());
                            }
                            writer.println (
                                "        </table>\n" +
                                "    </td>\n" +
                                "</tr>");
                        }
                        List<APIParameterDefinition> list = method.getParameters ();
                        if (!list.isEmpty ()) {
                            writer.println (
                                "<tr>\n" +
                                "    <th>Parameters</th>\n" +
                                "    <td>\n" +
                                "        <table class=\"sub-table\">\n" +
                                "            <tr class=\"sub-table-header\">\n" +
                                "                <th>参数名</th>\n" +
                                "                <th>参数类型</th>\n" +
                                "                <th>描述</th>\n" +
                                "            </tr>");
                            for (APIParameterDefinition pd : list) {
                                writer.printf (
                                "<tr>\n" +
                                "    <th>%s</th>\n" +
                                "    <td>%s</td>\n" +
                                "    <td>%s</td>\n" +
                                "</tr>%n", pd.getName(), pd.getType().getCanonicalName(), pd.getDescription());
                            }
                            writer.println (
                                    "        </table>\n" +
                                    "    </td>\n" +
                                    "</tr>");
                        }
                        if (!method.getResultDefinition ().isEmpty ()) {
                            writer.println (
                                "<tr>\n" +
                                "    <th>Returns</th>\n" +
                                "    <td>\n" +
                                "        <table class=\"sub-table\">\n" +
                                "            <tr class=\"sub-table-header\">\n" +
                                "                <th>字段名</th>\n" +
                                "                <th>是否必须</th>\n" +
                                "                <th>字段类型</th>\n" +
                                "                <th>描述</th>\n" +
                                "            </tr>");
                            List<ResultFieldDefinition> results = method.getResultDefinition ();
                            for (ResultFieldDefinition field : results) {
                                writer.printf (
                                    "<tr>\n" +
                                    "    <th>%s</th>\n" +
                                    "    <td>%s</td>\n" +
                                    "    <td>%s</td>\n" +
                                    "    <td>%s</td>\n" +
                                    "</tr>", field.getName(), field.isMandatory() ? "Y" : "",
                                    field.getType(), field.getDescription() == null ? "" : field.getDescription());
                            }
                            writer.println (
                                "    </table>\n" +
                                "    </td>\n" +
                                "</tr>");
                        }
                        writer.println ("</table>");
                    }
                    writer.println ("</div>");
                }
                writer.println ("</div>");
            }
            writer.println ("</div>");
            writer.println (
                "<script type=\"text/javascript\" language=\"javascript\">\n" +
                "    var button = document.getElementById ('close-button'),\n" +
                "          list = document.getElementById ('content-table-list'),\n" +
                "         table = document.getElementById ('content-table');\n" +
                "    button.onclick = function () {\n" +
                "        if (button.innerHTML == '+') {\n" +
                "            table.className = 'content-table';\n" +
                "            list.style.display = 'block';\n" +
                "            button.innerHTML = '-';\n" +
                "        } else if (button.innerHTML == '-') {\n" +
                "            table.className = 'content-table transparent';\n" +
                "            list.style.display = 'none';\n" +
                "            button.innerHTML = '+';\n" +
                "        }\n" +
                "    }\n" +
                "</script>");
        }
        writer.println ("</body></html>");
    }
}